package craky.keeper.view;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.annotation.SuppressLint;
import android.app.FragmentManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import craky.keeper.bean.KeeperObject;
import craky.keeper.bean.ResultSet;
import craky.keeper.bean.User;
import craky.keeper.client.ContextMenuDialog;
import craky.keeper.client.DetailActivity;
import craky.keeper.client.KeeperActivity;
import craky.keeper.client.PullDownListener;
import craky.keeper.client.R;
import craky.keeper.client.task.KeeperTask;
import craky.keeper.client.task.LoadTask;
import craky.keeper.util.KeeperUtil;

public class KeeperListView extends ListView
{
    private static final String KEY_OBJECT = "object";

    private static final String KEY_DATE = "date";

    private static final String KEY_SUMMARY = "summary";

    private static final String KEY_AMOUNT = "amount";

    private boolean firstFinished, isPay, pressable;

    private KeeperActivity activity;

    private ImageView firstLoadImage;

    private ListFooter footer;

    private long loadActionTime, loadMoreActionTime, lastUpdateTime;

    private LoadTask loadTask, loadMoreTask;

    private KeeperTask deleteTask;

    private SimpleAdapter adapter;

    private List<Map<String, Object>> listValues;

    private PullDownListener pullDownListener;

    private ListItem currentItem;

    @SuppressLint("InflateParams")
    public KeeperListView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        this.activity = (KeeperActivity)context;
        this.isPay = true;
        this.pressable = true;
        this.listValues = new ArrayList<Map<String, Object>>();
        String[] from = {KEY_DATE, KEY_SUMMARY, KEY_AMOUNT};
        int[] to = {R.id.itemDate, R.id.itemSummary, R.id.itemAmount};
        footer = (ListFooter)activity.getLayoutInflater().inflate(R.layout.list_footer, null);
        adapter = new SimpleAdapter(context, listValues, R.layout.list_item, from, to);
        this.addFooterView(footer);
        this.setAdapter(adapter);
        this.setDivider(new ColorDrawable(0xFFDFE0E0));
        this.setDividerHeight(1);
        this.setOnItemClickListener(new AdapterView.OnItemClickListener()
        {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id)
            {
                if((pullDownListener == null || pullDownListener.isItemClickable()) && view instanceof ListItem)
                {
                    ((ListItem)view).setPosition(position);
                    showDetail((ListItem)view);
                }
            }
        });

        if(KeeperUtil.currentUser.getPurview() <= User.ADMIN)
        {
            initContextMenu();
        }
    }

    private void initContextMenu()
    {
        this.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener()
        {
            ContextMenuDialog menuDialog;

            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id)
            {
                if((pullDownListener == null || pullDownListener.isLongClickable()) && view instanceof ListItem)
                {
                    if(menuDialog == null)
                    {
                        menuDialog = new ContextMenuDialog(activity, KeeperListView.this);
                    }

                    if(pullDownListener != null)
                    {
                        pullDownListener.setPullable(false);
                    }

                    ((ListItem)view).setPosition(position);
                    menuDialog.setListItem((ListItem)view);
                    FragmentManager fm = activity.getFragmentManager();
                    menuDialog.show(fm, null);
                    return true;
                }
                else
                {
                    return false;
                }
            }
        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent e)
    {
        boolean consumed = false;

        if(pullDownListener != null)
        {
            consumed = pullDownListener.onTouch(this, e);
        }

        if(!consumed)
        {
            consumed = super.onTouchEvent(e);
        }

        return consumed;
    }

    public void loadDatasFirst()
    {
        firstLoadImage = (ImageView)activity.findViewById(R.id.firstLoadImage);
        float pivot = firstLoadImage.getWidth() / 2.0f;
        Animation animation = new RotateAnimation(0, Integer.MAX_VALUE / 3.0f, pivot, pivot);
        animation.setInterpolator(KeeperUtil.LINEAR_INTERPOLATOR);
        animation.setDuration(Integer.MAX_VALUE);
        firstLoadImage.startAnimation(animation);
        loadDatas();
    }

    public void loadDatas()
    {
        cancelLoadMore();
        footer.setEnabled(false);
        loadTask = new LoadTask(this, loadActionTime = System.currentTimeMillis(), false, null);
        loadTask.execute(isPay);
    }

    public void loadMore()
    {
        loadMoreTask = new LoadTask(this, loadMoreActionTime = System.currentTimeMillis(), true, getDataIDs());
        loadMoreTask.execute(isPay);
    }

    public void dealLoadResult(LoadTask task, String errorMessage, List<? extends KeeperObject> dataList, boolean notifyHeader)
    {
        if(this.loadActionTime != task.getActionTime())
        {
            return;
        }

        boolean success = errorMessage == null;
        boolean cancel = dataList == null;

        if(!firstFinished)
        {
            firstLoadImage.clearAnimation();
            firstLoadImage = null;
        }
        else if(notifyHeader && pullDownListener != null)
        {
            pullDownListener.refreshFinished(errorMessage, cancel);
        }

        if(!success && !firstFinished)
        {
            activity.showToast(errorMessage, true);
        }
        else if(success && !cancel)
        {
            refreshViewData(dataList, false);
            footer.loadFinished(dataList.size() == LoadTask.ITEMS_PER_LOAD);
        }

        this.firstFinished = true;
        this.loadTask = null;
        this.loadActionTime = 0;
        footer.resetEnabled();
    }

    public void dealLoadMoreResult(LoadTask task, String errorMessage, ResultSet resultSet)
    {
        if(this.loadMoreActionTime != task.getActionTime())
        {
            return;
        }

        boolean hasMoreData = true;

        if(errorMessage != null)
        {
            activity.showToast(errorMessage, true);
        }
        else if(resultSet != null)
        {
            List<? extends KeeperObject> dataList = isPay? resultSet.getPayList(): resultSet.getIncomeList();

            if(dataList == null)
            {
                activity.showToast(activity.getResources().getString(R.string.data_overdued), true);
            }
            else
            {
                refreshViewData(dataList, true);
                hasMoreData = dataList.size() == LoadTask.ITEMS_PER_LOAD;
            }
        }

        footer.loadFinished(hasMoreData);
        this.loadMoreTask = null;
        this.loadMoreActionTime = 0;
    }

    public void dealDeleteResult(KeeperTask task, String errorMessage, ResultSet resultSet)
    {
        if(this.deleteTask != task)
        {
            return;
        }

        activity.startOrStopTask(false, errorMessage);

        if(resultSet != null)
        {
            if(resultSet.getOldUpdateTime() == this.getLastUpdateTime())
            {
                this.setLastUpdateTime(resultSet.getLastUpdateTime());
            }

            listValues.remove(currentItem.getPosition());
            adapter.notifyDataSetChanged();
            activity.showToast(activity.getResources().getString(R.string.delete_success), false);
        }

        this.deleteTask = null;
    }

    private void refreshViewData(List<? extends KeeperObject> dataList, boolean append)
    {
        if(!append)
        {
            listValues.clear();
        }

        Map<String, Object> map;

        for(KeeperObject data: dataList)
        {
            map = new HashMap<String, Object>();
            map.put(KEY_OBJECT, data);
            map.put(KEY_DATE, KeeperUtil.DATE_FORMAT.format(data.getDate()));
            map.put(KEY_SUMMARY, data.getSummary());
            map.put(KEY_AMOUNT, data.getAmountString());
            listValues.add(map);
        }

        adapter.notifyDataSetChanged();
    }

    public void refreshViewData(KeeperObject keeperData, boolean isAdd)
    {
        Map<String, Object> map;

        if(isAdd)
        {
            map = new HashMap<String, Object>();
            listValues.add(0, map);
        }
        else
        {
            map = listValues.get(currentItem.getPosition());
        }

        map.put(KEY_OBJECT, keeperData);
        map.put(KEY_DATE, KeeperUtil.DATE_FORMAT.format(keeperData.getDate()));
        map.put(KEY_SUMMARY, keeperData.getSummary());
        map.put(KEY_AMOUNT, keeperData.getAmountString());
        adapter.notifyDataSetChanged();

        if(isAdd)
        {
            this.setSelection(0);
        }
    }

    public void cancelLoad(boolean notifyHeader)
    {
        if(pullDownListener != null)
        {
            pullDownListener.beforeRefreshFinished();
        }

        if(loadTask != null && loadTask.getStatus() != AsyncTask.Status.FINISHED)
        {
            loadTask.cancel(false);
            dealLoadResult(loadTask, null, null, notifyHeader);
        }
        else
        {
            footer.resetEnabled();
            loadTask = null;
            loadActionTime = 0;
        }
    }

    public void cancelLoadMore()
    {
        if(loadMoreTask != null && loadMoreTask.getStatus() != AsyncTask.Status.FINISHED)
        {
            loadMoreTask.cancel(false);
            dealLoadMoreResult(loadMoreTask, null, null);
        }
        else
        {
            footer.resetEnabled();
            loadMoreTask = null;
            loadMoreActionTime = 0;
        }
    }

    public void cancelDelete()
    {
        if(deleteTask != null)
        {
            deleteTask.cancel(false);
            deleteTask = null;
            activity.startOrStopTask(false, null);
        }
    }

    private List<Integer> getDataIDs()
    {
        List<Integer> ids = null;

        if(!listValues.isEmpty())
        {
            ids = new ArrayList<Integer>();

            for(Map<String, Object> itemMap: listValues)
            {
                ids.add(((KeeperObject)itemMap.get(KEY_OBJECT)).getId());
            }
        }

        return ids;
    }

    private void showDetail(ListItem item)
    {
        Intent intent = new Intent(activity, DetailActivity.class);
        KeeperObject data = (KeeperObject)listValues.get(item.getPosition()).get(KEY_OBJECT);
        intent.putExtra(KeeperUtil.KEY_KEEPER_DATA, data);
        intent.putExtra(KeeperUtil.KEY_IS_PAY, isPay);
        intent.putExtra(KeeperUtil.KEY_ACTION, KeeperUtil.ACTION_SHOW_DETAIL);
        activity.startActivity(intent);
    }

    public void addItem()
    {
        Intent intent = new Intent(activity, DetailActivity.class);
        intent.putExtra(KeeperUtil.KEY_IS_PAY, isPay);
        intent.putExtra(KeeperUtil.KEY_ACTION, KeeperUtil.ACTION_ADD);
        activity.startActivityForResult(intent, KeeperUtil.REQUEST_CODE_ADD);
    }

    public void deleteItem(ListItem item)
    {
        this.currentItem = item;
        KeeperObject data = (KeeperObject)listValues.get(item.getPosition()).get(KEY_OBJECT);
        deleteTask = new KeeperTask(activity, null, data, KeeperUtil.ACTION_DELETE);
        activity.startOrStopTask(true, null);
        deleteTask.execute(isPay);
    }

    public void modifyItem(ListItem item)
    {
        this.currentItem = item;
        Intent intent = new Intent(activity, DetailActivity.class);
        KeeperObject data = (KeeperObject)listValues.get(item.getPosition()).get(KEY_OBJECT);
        intent.putExtra(KeeperUtil.KEY_KEEPER_DATA, data);
        intent.putExtra(KeeperUtil.KEY_IS_PAY, isPay);
        intent.putExtra(KeeperUtil.KEY_ACTION, KeeperUtil.ACTION_MODIFY);
        activity.startActivityForResult(intent, KeeperUtil.REQUEST_CODE_MODIFY);
    }

    public void setPay(boolean isPay)
    {
        this.isPay = isPay;
    }

    public boolean isPay()
    {
        return this.isPay;
    }

    public boolean isFirstFinished()
    {
        return this.firstFinished;
    }

    public PullDownListener getPullDownListener()
    {
        return this.pullDownListener;
    }

    public void setPullDownListener(PullDownListener pullDownListener)
    {
        this.pullDownListener = pullDownListener;
    }

    @Override
    public void setPressed(boolean pressed)
    {
        if(!pressed || pressable)
        {
            super.setPressed(pressed);
        }
    }

    public boolean isPressable()
    {
        return this.pressable;
    }

    public void setPressable(boolean pressable)
    {
        this.pressable = pressable;
    }

    public long getLastUpdateTime()
    {
        return this.lastUpdateTime;
    }

    public void setLastUpdateTime(long lastUpdateTime)
    {
        this.lastUpdateTime = lastUpdateTime;
    }
}